﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using Logic.Packet;
using Logic;
using Logic.Packet.Factories;
using PacketDotNet;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using GameProxy;

namespace GameProxy
{
    public class Proxy : BackgroundWorker
    {

        public Proxy(string ip)
        {
            IP = ip;
        }

        #region Properties
        public IPEndPoint m_listenEp = null;
        public EndPoint m_connectedClientEp = null;
        public IPEndPoint m_sendEp = null;
        public Socket m_UdpListenSocket = null;
        public Socket m_UdpSendSocket = null;
        public static Queue<byte[]> SendQueue = new Queue<byte[]>();
        public static Queue<byte[]> ReceiveQueue = new Queue<byte[]>();
        public string IP;
        #endregion

        #region Events
        public event EventHandler<SendEventArgs> Send;
        public event EventHandler<ReceiveEventArgs> Receive;
        #endregion

        /// <summary>
        ///  Invoke the Send event
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnSend(SendEventArgs e)
        {
            if (Send != null)
                Send(this, e);
        }

        /// <summary>
        /// Invoke the Receive event
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnReceive(ReceiveEventArgs e)
        {
            if (Receive != null)
                Receive(this, e);
        }


        protected override void OnDoWork(DoWorkEventArgs e)
        {
            // Creates Listener UDP Server
            m_listenEp = new IPEndPoint(IPAddress.Any, 11677);
            m_UdpListenSocket = new Socket(m_listenEp.Address.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
            m_UdpListenSocket.Bind(m_listenEp);
            //Connect to zone IP EndPoint
            m_sendEp = new System.Net.IPEndPoint(IPAddress.Parse(IP), 11677);
            m_connectedClientEp = new System.Net.IPEndPoint(IPAddress.Any, 11677);


            while (true)
            {
                if (m_UdpListenSocket.Available > 0)
                {
                    byte[] buffer = new byte[1024];
                    int size = m_UdpListenSocket.ReceiveFrom(buffer, ref m_connectedClientEp); //client to listener
                    byte[] data = new byte[size];
                    Array.Copy(buffer, data, size);
                    // Connect to UDP Game Server.
                    if (m_UdpSendSocket == null)
                        m_UdpSendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    //Send to Server
                    SendQueue.Enqueue(data);
                    OnSend(new SendEventArgs() { Data = data });
                    m_UdpSendSocket.SendTo(buffer, size, SocketFlags.None, m_sendEp); //listener to server.

                }

                if (m_UdpSendSocket != null && m_UdpSendSocket.Available > 0)
                {
                    byte[] buffer = new byte[1024];
                    int size = m_UdpSendSocket.Receive(buffer); //server to client.
                    byte[] data = new byte[size];
                    Array.Copy(buffer, data, size);
                    //Send to Client
                    ReceiveQueue.Enqueue(data);
                    OnReceive(new ReceiveEventArgs() { Data = data });
                    //ReceiveQueue.Dequeue();
                    m_UdpListenSocket.SendTo(buffer, size, SocketFlags.None, m_connectedClientEp); //listner

                }
            }
        }

        public void Attach(IProxyable logger)
        {
            Receive += logger.Receive;
            Send += logger.Send;
        }

        public void Detach(IProxyable logger)
        {
            Receive -= logger.Receive;
            Send -= logger.Send;
        }


        public void InjectIncoming(byte[] packet)
        {
            SendQueue.Enqueue(packet);
        }

        public void InjectReceiving(byte[] packet)
        {
            ReceiveQueue.Enqueue(packet);
        }
    }
}
